package util.arff;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.StringWriter;
import java.text.DecimalFormat;
import java.util.HashMap;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;

public class FastaArffGenerator extends AbstractArffGenerator{
    private String separator = System.getProperty("file.separator");
    private String db; //path to input file
    private String output;
    private String root;
    private String temp;
    private boolean includeEnergy;
    private HashMap<Integer, String> numberToNameMap = new HashMap<Integer, String>();
    private HashMap<Integer, String> numberToSequenceMap = new HashMap<Integer, String>();

    public FastaArffGenerator(String db, String root, boolean includeEnergy) {
	super();
	this.includeEnergy = includeEnergy;
	this.db = db;
	this.root = root;
	this.output = this.root + separator + "out";
	this.temp = this.root + separator + "temp";
	File file = new File(this.temp);
	file.mkdirs();
	this.considerZeros = false;
    }
    
    public HashMap<Integer, String> getNumberToNameMap()
    {
    	return numberToNameMap;
    }
    
    public HashMap<Integer, String> getNumberToSequenceMap()
    {
    	return numberToSequenceMap;
    }
    
    public void processFastaFile() throws IOException {
	BufferedReader reader = new BufferedReader(new FileReader(db));
	String thisLine = null;
	int idCounter = 0;
	BufferedWriter writer = null;
	while ((thisLine = reader.readLine())!= null) {
	    if (thisLine.startsWith(">")) {
		if (writer != null) {
		    writer.close();
		}
		idCounter += 1;
		String path = temp + separator + idCounter;
		File dir = new File(path);
		dir.mkdirs();
		File file = new File(path + separator + "seq.fasta");
		if (!file.exists()) {
		    file.createNewFile();
		}
		writer= new BufferedWriter(new FileWriter(file));
		numberToNameMap.put(idCounter, thisLine);
	    }
	    writer.append(thisLine);
	    writer.newLine();
	}
	reader.close();
	writer.close();
    }
    
    public void generatePPOutput() throws IOException, InterruptedException {
		for (Integer id : numberToNameMap.keySet()) {
			Process process = Runtime.getRuntime().exec(createBatchCommand(id));
			process.waitFor();
			StringWriter writer1 = new StringWriter();
			IOUtils.copy(process.getErrorStream(), writer1, "UTF-8");
			StringWriter writer2 = new StringWriter();
			IOUtils.copy(process.getInputStream(), writer2, "UTF-8");
			System.out.println(writer1.toString());
			System.out.println(writer2.toString());
			writer1.close();
			writer2.close();
		}
	
		try {
			File dir = new File(temp);
			FileUtils.deleteDirectory(dir);
			System.out.println("temp deleted");
	    } catch(Exception ex) {
	    	try {
	    		
	    		Thread.sleep(5000);
	    		System.gc();
	    		File dir = new File(temp);
				FileUtils.deleteDirectory(dir);
				System.out.println("temp deleted");
	    	} catch(Exception ex2) {
	    		System.err.println("Fehler beim loeschen der temp-verzeichnisse: "+ex.getMessage());
	    	ex.printStackTrace();
	    	}
	    }

    }
    
    public String createBatchCommand(Integer id) {
	String result = separator +
	"usr" +
	separator +
	"bin" +
	separator +
	"predictprotein --seqfile " +
	temp + separator + id + separator + "seq.fasta" +
	" --target=all --target=optional --output-dir " +
	output + separator + id;
	return result;
    }

    @Override
    public void generateArff() {
	for (Integer id : numberToNameMap.keySet()) {
	    try {
		generateArffForId(id);
	    } catch (Exception e) {
		e.printStackTrace();
	    }
	}
    }
    
    public void generateArffForId(int id) throws IOException {
	String outputPath = output + separator + id;
	File dir = new File(outputPath);
	dir.mkdirs();
	File f = new File(output + separator + id + separator + "prot.arff");
            if(!f.exists()){
            	f.createNewFile();
            }
    	BufferedWriter writer = new BufferedWriter(new FileWriter(f));
    	writer.write("%Created by Group77");
    	writer.newLine();
    	writer.write("@RELATION\t'" + "prot.arff'");
    	writer.newLine();
    	writer.newLine();
    	writer.write("@ATTRIBUTE\tpos\tNUMERIC");
    	writer.newLine();
    	writer.write("@ATTRIBUTE\trelpos\tNUMERIC");
    	writer.newLine();
	if (includeEnergy) {
		writer.write("@ATTRIBUTE\tdeltagapp\tNUMERIC");
		writer.newLine();
	}
    	if (considerZeros) {
    		writer.write("@ATTRIBUTE\tclass\t{+,-,0}");
    	} else {
    	    writer.write("@ATTRIBUTE\tclass\t{+,-}");
    	}
    	writer.newLine();
    	writer.newLine();
    	writer.write("@DATA");
    	int seqLength = getSeqLength(id);
    	DecimalFormat dFormat = new DecimalFormat("#0.00");
    	for (int i = 0; i < seqLength; i++) {
    		writer.newLine();
    		
    		String aaSequence = new String(getSeq(id));
    		numberToSequenceMap.put(id, aaSequence);
    		
    		String energyString = includeEnergy ? calculateEnergy(getSeq(id), i) + "," : "";
    		writer.write(i + ","
    			+ dFormat.format(Math.round(((double)i / (seqLength - 1)) * 100) / 100.0) + "," 
    			+ energyString
    			+ "?");
    	}
    	writer.close();
    }

    private char[] getSeq(int id) throws IOException {
	File file = new File(temp + separator + id + separator + "seq.fasta");
	BufferedReader reader = new BufferedReader(new FileReader(file));
	reader.readLine();
	String line = null;
	String seq = "";
	while ((line = reader.readLine()) != null) {
	    seq += line;
	}
	return seq.toCharArray();

    }

    private int getSeqLength(int id) throws IOException {
	File file = new File(temp + separator + id + separator + "seq.fasta");
	BufferedReader reader = new BufferedReader(new FileReader(file));
	reader.readLine();
	String line = null;
	String seq = "";
	while ((line = reader.readLine()) != null) {
	    seq += line;
	}
	return seq.length();
    }
    
    

}
